/*****************************************************************************
 * Copyright (c) 2019, 2021 CEA LIST, Christian W. Damus, and others.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *   Nicolas FAUVERGUE (CEA LIST) nicolas.fauvergue@cea.fr - Initial API and implementation
 *   Christian W. Damus - bugs 570097, 573788, 573986
 *
 *****************************************************************************/

package org.eclipse.papyrus.toolsmiths.validation.properties.internal.constants;

import java.util.Optional;

import org.eclipse.core.resources.IMarker;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.papyrus.toolsmiths.validation.common.checkers.CommonProblemConstants;
import org.eclipse.papyrus.toolsmiths.validation.common.checkers.IPluginChecker2;
import org.eclipse.papyrus.toolsmiths.validation.common.quickfix.CommonMarkerResolutionUtils;

/**
 * The <em>Properties Context</em> plug-in validation constants.
 */
public class PropertiesPluginValidationConstants {

	/**
	 * Marker type for the validation of properties plug-ins.
	 */
	public static final String PROPERTIES_PLUGIN_VALIDATION_MARKER_TYPE = "org.eclipse.papyrus.toolsmiths.validation.properties.diagnostic"; //$NON-NLS-1$

	/**
	 * The extension point identifier for <em>Properties Context</em> model resources.
	 */
	public static final String CONTEXTS_EXTENSION_POINT_IDENTIFIER = "org.eclipse.papyrus.infra.properties.contexts"; //$NON-NLS-1$

	/** The environment models extension point element name. */
	public static final String E_CONTEXT = "context"; //$NON-NLS-1$
	public static final String A_CONTEXT_MODEL = "contextModel"; //$NON-NLS-1$

	/**
	 * The extension point identifier for <em>Properties Environment</em> model resources.
	 */
	public static final String ENVIRONMENTS_EXTENSION_POINT_IDENTIFIER = "org.eclipse.papyrus.infra.properties.environments"; //$NON-NLS-1$

	/** The environment models extension point element name. */
	public static final String E_ENVIRONMENT = "environment"; //$NON-NLS-1$
	public static final String A_ENVIRONMENT_MODEL = "environmentModel"; //$NON-NLS-1$

	/** The architecture models extension point attribute name for the resource path. */
	public static final String ATTR_PATH = "path"; //$NON-NLS-1$

	/**
	 * Marker attribute indicating the URI of the object to set in a reference to fix the problem of
	 * an inconsistent property type, widget type, or other issue of the same "wrong object referenced" kind.
	 */
	public static final String MARKER_ATTR_REF = "object_to_reference"; //$NON-NLS-1$

	/**
	 * Marker attribute indicating value to set in an attribute to fix the problem of
	 * an inconsistent property type, widget type, or other issue of the same "wrong object referenced" kind.
	 */
	public static final String MARKER_ATTR_VALUE = "value_to_set"; //$NON-NLS-1$

	/**
	 * Marker attribute indicating which layout generator must be used to fix missing
	 * attributes or elements.
	 */
	public static final String MARKER_ATTR_LAYOUT_GENERATOR = "layout_generator"; //$NON-NLS-1$

	/** Problem IDs for the markers generated by properties plug-in validation. */
	public static final int PROBLEM_ID_BASE = CommonProblemConstants.MAX_PROBLEM_ID + 0x01;
	public static final int MISSING_CONTEXT_MODEL_EXTENSION_ID = PROBLEM_ID_BASE + 0x00;
	public static final int MISSING_ENVIRONMENT_MODEL_EXTENSION_ID = PROBLEM_ID_BASE + 0x01;
	public static final int OBSOLETE_DATA_CONTEXT_PACKAGE = PROBLEM_ID_BASE + 0x02;
	public static final int MISSING_DATA_CONTEXT_ELEMENT = PROBLEM_ID_BASE + 0x03;
	public static final int OBSOLETE_DATA_CONTEXT_ELEMENT = PROBLEM_ID_BASE + 0x04;
	public static final int MISSING_DATA_CONTEXT_PROPERTY = PROBLEM_ID_BASE + 0x05;
	public static final int OBSOLETE_DATA_CONTEXT_PROPERTY = PROBLEM_ID_BASE + 0x06;
	public static final int INCONSISTENT_DATA_CONTEXT_PROPERTY_TYPE = PROBLEM_ID_BASE + 0x07;
	public static final int INCONSISTENT_WIDGET_TYPE = PROBLEM_ID_BASE + 0x08;
	public static final int RENAMED_PROPERTY = PROBLEM_ID_BASE + 0x09;
	public static final int RENAMED_CLASS = PROBLEM_ID_BASE + 0x0a;
	public static final int RENAMED_PACKAGE = PROBLEM_ID_BASE + 0x0b;
	public static final int MISSING_DATA_CONTEXT_PACKAGE = PROBLEM_ID_BASE + 0x0c;
	public static final int OBSOLETE_DATA_CONTEXT_ROOT = PROBLEM_ID_BASE + 0x0d;
	public static final int UNRESOLVED_CONSTRAINT_CLASS = PROBLEM_ID_BASE + 0x0e;
	public static final int UNRESOLVED_CONSTRAINT_CLASS_MULTIPLE_CHOICE = PROBLEM_ID_BASE + 0x0f;
	public static final int INCONSISTENT_DATA_CONTEXT_PROPERTY_MULTIPLICITY = PROBLEM_ID_BASE + 0x10;
	public static final int MAX_PROBLEM_ID = PROBLEM_ID_BASE + 0x3f;

	/**
	 * Get the suggested object to set in the problematic reference.
	 *
	 * @param <T>
	 *            the object type
	 * @param marker
	 *            the marker describing the problem
	 * @param type
	 *            the object type
	 * @param domain
	 *            the contextual editing domain
	 * @return the object to set in the problematic reference of the object targeted by the marker
	 */
	public static <T extends EObject> Optional<T> getObjectToReference(IMarker marker, Class<T> type, EditingDomain domain) {
		return CommonMarkerResolutionUtils.getModelObject(marker, MARKER_ATTR_REF, type, domain);
	}

	/**
	 * Create a marker attribute to encode the reference to an object to set in the problematic model element.
	 *
	 * @param object
	 *            an object to encode as a reference in a marker
	 * @return the marker attribute
	 */
	public static IPluginChecker2.MarkerAttribute objectToReference(EObject object) {
		return new IPluginChecker2.MarkerAttribute(MARKER_ATTR_REF, EcoreUtil.getURI(object));
	}

	/**
	 * Get the suggested value to set in the problematic attribute.
	 *
	 * @param <V>
	 *            the value type
	 * @param marker
	 *            the marker describing the problem
	 * @param type
	 *            the value type
	 * @param dataType
	 *            the EMF representation of the value type, used to restore non-primitive values
	 * @return the value to set in the problematic attribute of the object targeted by the marker
	 */
	public static <V> Optional<V> getValueToSet(IMarker marker, Class<V> type, EDataType dataType) {
		return CommonMarkerResolutionUtils.getValue(marker, MARKER_ATTR_VALUE, type, dataType);
	}

	/**
	 * Create a marker attribute to encode the value of an attribute to set in the problematic model element.
	 *
	 * @param value
	 *            an attribute value to encode in a marker
	 * @param dataType
	 *            the EMF representation of the value type, used to restore non-primitive values
	 * @return the marker attribute
	 */
	public static IPluginChecker2.MarkerAttribute valueToSet(Object value, EDataType dataType) {
		if (value instanceof Boolean) {
			return new IPluginChecker2.MarkerAttribute(MARKER_ATTR_VALUE, (boolean) value);
		} else if (value instanceof Integer) {
			return new IPluginChecker2.MarkerAttribute(MARKER_ATTR_VALUE, (int) value);
		} else {
			return new IPluginChecker2.MarkerAttribute(MARKER_ATTR_VALUE, EcoreUtil.convertToString(dataType, value));
		}
	}

}
